package com.fdb.efp.console.api.rest;

import com.fdb.basic.framework.core.constant.ApplicationConstance;
import com.fdb.basic.framework.core.constant.BaseConstant;
import com.fdb.basic.framework.core.constant.ResponseData;
import com.fdb.basic.framework.core.util.StringUtil;
import com.fdb.basic.framework.core.util.TimeUtil;
import com.fdb.efp.console.executor.util.AbstractController;
import com.fdb.efp.console.service.FlowCommonService;
import com.fdb.efp.console.service.OutsDistrCaseComnService;
import com.fdb.efp.console.common.RiskColltConstant;
import com.fdb.efp.console.service.facade.CaseDistrRatioService;
import com.fdb.efp.console.service.facade.ColltTaskDistrService;
import com.fdb.efp.console.service.facade.ColltTaskInfoService;
import com.fdb.efp.console.service.facade.OutsTaskDistrMainService;
import com.fdb.efp.console.service.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RestController
@RequestMapping("/api")
public class OutsTaskDistrMainForFlowController extends AbstractController {

    @Autowired
    @Qualifier("outsTaskDistrMainService")
    private OutsTaskDistrMainService outsTaskDistrMainService;

    @Autowired
    @Qualifier("colltTaskInfoService")
    private ColltTaskInfoService colltTaskInfoService;

    @Autowired
    @Qualifier("caseDistrRatioService")
    private CaseDistrRatioService caseDistrRatioService;

    @Autowired
    @Qualifier("colltTaskDistrService")
    private ColltTaskDistrService colltTaskDistrService;

    @Autowired
    private FlowCommonService flowCommonService;

    @Autowired
    private OutsDistrCaseComnService outsDistrCaseService;

    @Value("${DIVISIONLMT}")
    private BigDecimal divisionLmt;


    private final static String oneHand = RiskColltConstant.STD_HANDLE_TYPE_01;
    private final static String twoHand = RiskColltConstant.STD_HANDLE_TYPE_02;
    private final static String threeHand = RiskColltConstant.STD_HANDLE_TYPE_03;
    private final static String longHand = RiskColltConstant.STD_HANDLE_TYPE_04;

    private final static List<String> allHandTypeList = Arrays.asList(oneHand, twoHand, threeHand, longHand);

    /**
     * 审批页面获取信息
     * @param vo
     * @return
     */
    @RequestMapping(value = "/outs/task/distr/main/appr", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<List<OutsTaskDistrMainVO>> showOutsTaskDistrMainVOAppr(@RequestBody OutsTaskDistrMainVO vo) {
        List<OutsTaskDistrMainVO> outputVo = outsTaskDistrMainService.queryVoByColltBatchNo(vo);
        return getResponseData(outputVo);

    }

    /**
     *
     * 分案机构版本号展示
     *
     * @author wanglihua
     * @params  * @param null
     * @return
     * @since 2019/11/27 20:06
     * @date 2019/11/27 20:06
     * @version 0.1
     */
    @RequestMapping(value = "/distri/rate/orgver001" , method = RequestMethod.POST)
    public @ResponseBody ResponseData<List<CaseDistrRatioVO>> searchVersionNos(@RequestBody ColltTaskDistrVO vo) {
        List<CaseDistrRatioVO> outputVo = new ArrayList<>();
        try {
            if (!StringUtil.isNullorBank(vo.getVersionNo())) {
                logger.info("查询条件的分案机构分案比例版本号：" + vo.getVersionNo());
                outputVo = queryOrgInfosByVno(vo.getCooprOrgType(),vo.getVersionNo());
            } else {
                logger.info("获取合作状态为\"正常\"的合作机构的查询参数为：" + vo.toString());
                //获取合作状态为"正常"的合作机构
                List<CooprOrgInfoVO> cooprOrgInfos = flowCommonService.getDistrCooprOrgInfos(vo.getCooprOrgType());
                logger.info("合作状态为正常的合作机构" + cooprOrgInfos.toString());
                //获取合作机构编号集
                List<String> cooprOrgNos = cooprOrgInfos.stream().map(CooprOrgInfoVO::getCooprOrgNo).collect(Collectors.toList());
                //获取分案机构版本号
                outputVo = queryOrgInfos(vo.getCooprOrgType(),cooprOrgNos);
            }
            logger.info("有效的分案机构分案比例版本号：" + outputVo.toString());
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return getResponseData(outputVo);
    }
	
	private List<CaseDistrRatioVO> queryOrgInfosByVno(String cooprOrgType, String versionNo) throws Exception {
        logger.info("获取合作状态为“正常”的合作机构的查询参数为：合作机构类型代码:" + cooprOrgType + ",版本号:" + versionNo);
        CaseDistrRatioVO queryCondition = new CaseDistrRatioVO();
        queryCondition.setCooprOrgType(RiskColltConstant.COOPR_ORG_TYPE_001);
        queryCondition.setVersionNo(versionNo);
        List<CaseDistrRatioVO> orgList = caseDistrRatioService.getUsefulOrgsCaseInfos(queryCondition);
        if (Objects.isNull(orgList)) throw new Exception("查询到的合作机构为空，无法分案！");
        return orgList;
    }

    private List<CaseDistrRatioVO> queryOrgInfos(String cooprOrgType, List<String> cooprOrgNos) throws Exception {
        logger.info("获取合作状态为\"正常\"的合作机构的查询参数为：合作机构类型代码:" + cooprOrgType + ",有效机构号:" + cooprOrgNos.toString());
        CaseDistrRatioVO queryCondition = new CaseDistrRatioVO();
        queryCondition.setCooprOrgType(RiskColltConstant.COOPR_ORG_TYPE_001);
        queryCondition.setCooprOrgNos(cooprOrgNos);
        List<CaseDistrRatioVO> orgList = caseDistrRatioService.getUsefulOrgsCaseInfos(queryCondition);
        if (Objects.isNull(orgList)) throw new Exception("查询到的合作机构为空，无法分案！");
        return orgList;
    }

    /**
     * 分案机构比例详情展示
     *
     * @author wanglihua
     * @params  * @param null
     * @return
     * @since 2019/11/29 16:46
     * @date 2019/11/29 16:46
     * @version 0.1
     */
    @RequestMapping(value = "/distri/rate/orgver/detail001" , method = RequestMethod.POST)
    public @ResponseBody ResponseData<List<CaseDistrRatioVO>> getVersionNos(@RequestBody CaseDistrRatioVO caseDistrRatioVO) {
        List<CaseDistrRatioVO> outputVo = caseDistrRatioService.getOrgListByPage(caseDistrRatioVO);
        logger.info("经确认查询得到的分案机构信息：" + outputVo.toString());
        return getResponseData(outputVo);
    }

    /**
     * 委外分案
     * <p>
     *    获取分案催收任务
     *    获取分案催收机构信息，案件占比信息
     *    插入outs_task_distr_main
     *    对案件进行分案
     *    发起流程
     *    insert分案申请信息
     *    插入collt_task_distr
     *    更新collt_task_info
     *
     * @param vo
     * @return
     */
    @RequestMapping(value = "/outs/task/distr/case", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<Integer> outsTaskDistrCase(@RequestBody OutsTaskDistrMainVO vo) {
        ResponseData<Integer> outputVo = new ResponseData<>();
        try {
            setUserInfoToVO(vo);
            //获取委外催收任务
            List<ColltTaskInfoVO> distrColltTasks = getDistrColltTasks();

            /*//获取合作状态为"正常"的委外机构
            List<CooprOrgInfoVO> distrCooprOrgInfos = flowCommonService.getDistrCooprOrgInfos(RiskColltConstant.COOPR_ORG_TYPE_001);
            List<String> cooprOrgNos = distrCooprOrgInfos.stream().map(CooprOrgInfoVO::getCooprOrgNo).collect(Collectors.toList());
            //获取版本状态=“”“”“”“”““””“”"生效"，审批状态=”"通过"的案件分配占比
            List<CaseDistrRatioVO> distrCaseDistrRatios = getDistrOrgsCaseRatios(cooprOrgNos);*/
            /*
            *
            * 完善分案机构信息获取流程
            * @author wanglihua
            * @date 2019/11/29 16:46
            * */
            List<CaseDistrRatioVO> distrCaseDistrRatios = caseDistrRatioService.getOrgList(vo.getVersionNo());
            logger.info("用于分案的机构信息：" + distrCaseDistrRatios.toString());

            //获取分案申请流水号
            String distrCaseApply = outsDistrCaseService.getDistrCaseApply();
            //获取分配批次号
            String batchNo = outsDistrCaseService.getBatchNo();

            //按照委外经手类型，将委外催收任务分组，并按照逾期金额从大到小排序
            Map<String, List<ColltTaskInfoVO>> colltTasksGroupByHandType = getColltTasksGroupByHandType(distrColltTasks);

            //按照手别案件占比，将案件分配比分组，并按照案件占比从大到小排序
            Map<String, List<CaseDistrRatioVO>> orgCaseRatiosByHandType = getOrgCaseRatiosByHandType(distrCaseDistrRatios);

            //所有手别的分配户数总和
            //long allHandTypeOrgs = orgCaseRatiosByHandType.values().stream().flatMap(i -> i.stream()).map(i -> 1).count();
            int allDistrCaseOrgs = distrCaseDistrRatios.size();

            //保存委外任务分配主表
            insertOutsTaskDistrMain(colltTasksGroupByHandType, orgCaseRatiosByHandType, batchNo, allDistrCaseOrgs);

            Map<String, Map<CaseDistrRatioVO, List<ColltTaskInfoVO>>> divCaseResult = new HashMap<>();
            try{
                //获取所有催收任务的分案结果
                divCaseResult = getDivCaseResult(colltTasksGroupByHandType, orgCaseRatiosByHandType);
            }catch (Exception e){
                //分案失败，删除委外任务分配主表信息
                vo.setColltBatchNo(batchNo);
                int num = outsTaskDistrMainService.deleteByPk(vo);
                if(num < 0){ logger.error("根据批次号:"+batchNo +"，删除委外任务分配主表信息失败！"); }
                throw e;
            }

            //发起案件分配申请流程
            outsDistrCaseService.submitDistrCaseAppr(distrCaseApply, batchNo, RiskColltConstant.STD_COLLT_WAY_03, vo);

            //参与分案的催收任务总金额（借据逾期金额的总和）
            BigDecimal colltTaskLmtTotal = distrColltTasks.stream()
                    .map(ColltTaskInfoVO::getOverLmt)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            //保存催收任务分配
            insertColltTaskDistr(divCaseResult, batchNo, colltTaskLmtTotal, distrColltTasks.size());

            //更新催收任务信息
            updateColltTaskInfos(divCaseResult, vo, batchNo);

            outputVo = getResponseData(1);
        } catch (Exception e) {
            logger.error("委外催收分案失败<======"+e.getMessage());
            e.printStackTrace();
            outputVo.setSuccess(false);
            outputVo.setMessage(e.getMessage());
            outputVo.setCode(ApplicationConstance.FAILURE);
        }
        return outputVo;
    }

    /**
     * 获取未分配的委外催收任务
     *
     * @return
     */
    private List<ColltTaskInfoVO> getDistrColltTasks() throws Exception {
        ColltTaskInfoVO colltTaskInfoVO = new ColltTaskInfoVO();
        colltTaskInfoVO.setColltWay(RiskColltConstant.STD_COLLT_WAY_03);
        colltTaskInfoVO.setIsTaskDistr(BaseConstant.NO_N);
        List<ColltTaskInfoVO> result = Optional.ofNullable(colltTaskInfoService.getDistrCaseColltTasks(colltTaskInfoVO))
                .orElseThrow(() -> new Exception("催收任务池暂无可分配的案件！"));
        //过滤逾期金额为空、手别为空的催收任务
        result = result.stream()
                .filter(colltTaskInfoVO1 -> { return null!=colltTaskInfoVO1.getOverLmt() && BigDecimal.ZERO.compareTo(colltTaskInfoVO1.getOverLmt())!=0 ;})
                .filter(colltTaskInfoVO2 -> { return StringUtil.isStrNotEmpty(colltTaskInfoVO2.getOutsHdleType()); })
                .collect(Collectors.toList());
        if(Objects.isNull(result) || result.isEmpty()){
            throw new Exception("催收任务池暂无有效的案件！");
        }
        return result;
    }

    /**
     * 根据委外经手类型，对参与分案的催收任务分组
     *
     * @param distrColltTasks
     * @return
     */
    private Map<String, List<ColltTaskInfoVO>> getColltTasksGroupByHandType(List<ColltTaskInfoVO> distrColltTasks) {
        Map<String, List<ColltTaskInfoVO>> result = new HashMap<>();

        for(String handType : allHandTypeList){
            List<ColltTaskInfoVO> colltTasks = Optional.ofNullable(distrColltTasks.stream().
                    filter(ctiVo -> {
                        return handType.equals(ctiVo.getOutsHdleType());
                    }).
                    sorted(Comparator.comparing(ColltTaskInfoVO::getOverLmt).reversed()).
                    collect(Collectors.toList())).orElse(new ArrayList<>());
            result.put(handType, colltTasks);
        }
        return result;
    }

    /**
     * 获取有效的委外催收机构案件占比 【来自表 case_distr_ratio】
     *
     * @return
     */
    private List<CaseDistrRatioVO> getDistrOrgsCaseRatios(List<String> cooprOrgNos) throws Exception {
        CaseDistrRatioVO caseDistrRatioVO = new CaseDistrRatioVO();
        caseDistrRatioVO.setCooprOrgType(RiskColltConstant.COOPR_ORG_TYPE_001);
        caseDistrRatioVO.setCooprOrgNos(cooprOrgNos);
        List<CaseDistrRatioVO> result = Optional.ofNullable(caseDistrRatioService.getOrgsCaseInfos(caseDistrRatioVO))
                .orElseThrow(() -> new Exception("无有效的委外机构参与分案！"));
        return result;
    }

    /**
     * 根据委外经手类型，对参与分案的委外机构案件占比分组
     *
     * @param distrCaseDistrRatios
     * @return
     */
    private Map<String, List<CaseDistrRatioVO>> getOrgCaseRatiosByHandType(List<CaseDistrRatioVO> distrCaseDistrRatios) {
        Map<String, List<CaseDistrRatioVO>> orgCaseRatioMap = new HashMap<>();

        List<CaseDistrRatioVO> caseDistrRatioOne = Optional.ofNullable(distrCaseDistrRatios.stream().
                filter(cdrVo -> {
                    return null != cdrVo.getPrimCaseRatio() && BigDecimal.ZERO.compareTo(cdrVo.getPrimCaseRatio()) != 0;
                }).
                sorted(Comparator.comparing(CaseDistrRatioVO::getPrimCaseRatio).reversed()).
                collect(Collectors.toList())).orElse(new ArrayList<>());
        orgCaseRatioMap.put(oneHand, caseDistrRatioOne);

        List<CaseDistrRatioVO> caseDistrRatioTwo = Optional.ofNullable(distrCaseDistrRatios.stream().
                filter(cdrVo -> {
                    return null != cdrVo.getSecdCaseRatio() && BigDecimal.ZERO.compareTo(cdrVo.getSecdCaseRatio()) != 0;
                }).
                sorted(Comparator.comparing(CaseDistrRatioVO::getSecdCaseRatio).reversed()).
                collect(Collectors.toList())).orElse(new ArrayList<>());
        orgCaseRatioMap.put(twoHand, caseDistrRatioTwo);

        List<CaseDistrRatioVO> caseDistrRatioThree = Optional.ofNullable(distrCaseDistrRatios.stream().
                filter(cdrVo -> {
                    return null != cdrVo.getThdCaseRatio() && BigDecimal.ZERO.compareTo(cdrVo.getThdCaseRatio()) != 0;
                }).
                sorted(Comparator.comparing(CaseDistrRatioVO::getThdCaseRatio).reversed()).
                collect(Collectors.toList())).orElse(new ArrayList<>());
        orgCaseRatioMap.put(threeHand, caseDistrRatioThree);

        List<CaseDistrRatioVO> caseDistrRatioLong = Optional.ofNullable(distrCaseDistrRatios.stream().
                filter(cdrVo -> {
                    return null != cdrVo.getLongAgeCaseRatio() && BigDecimal.ZERO.compareTo(cdrVo.getLongAgeCaseRatio()) != 0;
                }).
                sorted(Comparator.comparing(CaseDistrRatioVO::getLongAgeCaseRatio).reversed()).
                collect(Collectors.toList())).orElse(new ArrayList<>());
        orgCaseRatioMap.put(longHand, caseDistrRatioLong);

        return orgCaseRatioMap;
    }

    private void insertOutsTaskDistrMain(Map<String, List<ColltTaskInfoVO>> colltTasksGroupByHandType, Map<String, List<CaseDistrRatioVO>> orgCaseRatiosByHandType,
                                         String batchNo, int allDistrCaseOrgs) throws Exception {
        logger.info("======>批量插入委外任务分配主表开始<======批次号为:"+batchNo);
        List<OutsTaskDistrMainVO> batchInsertList = new ArrayList<>();
        List<ColltTaskInfoVO> allDistrColltTasks = colltTasksGroupByHandType.values()
                .stream()
                .flatMap(i -> i.stream())
                .collect(Collectors.toList());
        BigDecimal colltTaskLmtAll = allDistrColltTasks.stream()
                .map(ColltTaskInfoVO::getOverLmt)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        Iterator<String> handTypes = colltTasksGroupByHandType.keySet().iterator();
        while (handTypes.hasNext()){
            String handType = handTypes.next();
            List<ColltTaskInfoVO> colltTasks = colltTasksGroupByHandType.get(handType);
            BigDecimal handTypeLmtAll = colltTasks.stream()
                    .map(ColltTaskInfoVO::getOverLmt)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            int handOrgNum = orgCaseRatiosByHandType.get(handType).size();

            OutsTaskDistrMainVO taskDistrVO = createDistrColltTaskMain(handType, batchNo, handTypeLmtAll, colltTaskLmtAll, handOrgNum, allDistrCaseOrgs);

            batchInsertList.add(taskDistrVO);
        }
        int output = outsTaskDistrMainService.batchInsertVo(batchInsertList);
        if(output <= 0){
            throw new Exception("批量插入委外任务分配主表信息失败！");
        }
        logger.info("======>批量插入委外任务分配主表结束<======批次号为:"+batchNo);
    }

    private OutsTaskDistrMainVO createDistrColltTaskMain(String handType, String batchNo, BigDecimal handTypeLmtAll, BigDecimal colltTaskLmtAll, int handTypeColltTasks, int allDistrCaseOrgs) {
        String curTime = TimeUtil.getCurrentDateTime();
        OutsTaskDistrMainVO outsTaskDistrMainVO = new OutsTaskDistrMainVO();
        setUserInfoToVO(outsTaskDistrMainVO);
        outsTaskDistrMainVO.setColltBatchNo(batchNo);
        outsTaskDistrMainVO.setOutsHdleType(handType);
        outsTaskDistrMainVO.setDistrLmt(handTypeLmtAll);
        outsTaskDistrMainVO.setDistrCustNum(String.valueOf(handTypeColltTasks));
        outsTaskDistrMainVO.setDistrLmtRatio(handTypeLmtAll.divide(colltTaskLmtAll, 4, BigDecimal.ROUND_HALF_UP));
        //outsTaskDistrMainVO.setDistrCustsRatio(flowCommonService.getMarkSaid(handTypeColltTasks, allDistrCaseOrgs));
        outsTaskDistrMainVO.setDistrCustsRatio(handTypeColltTasks + "/" + allDistrCaseOrgs);
        outsTaskDistrMainVO.setDistrTime(curTime);
        outsTaskDistrMainVO.setOpUserCode(outsTaskDistrMainVO.getLoginUserId());
        outsTaskDistrMainVO.setOpOrgCode(outsTaskDistrMainVO.getLoginUserOrgCode());
        outsTaskDistrMainVO.setIsPassDistr(BaseConstant.NO_N);
        outsTaskDistrMainVO.setCreateUser(outsTaskDistrMainVO.getLoginUserId());
        outsTaskDistrMainVO.setCreateTime(curTime);
        outsTaskDistrMainVO.setLastChgUsr(outsTaskDistrMainVO.getLoginUserId());

        return outsTaskDistrMainVO;
    }

    /**
     * 批量插入催收任务分配表
     * @param divCaseResult 催收任务分案结果
     * @param batchNo 分配批次号
     * @param colltTaskLmtTotal 催收任务总逾期金额
     * @param colltTasksTotal   催收任务总数量
     * @throws Exception
     */
    private void insertColltTaskDistr(Map<String, Map<CaseDistrRatioVO, List<ColltTaskInfoVO>>> divCaseResult, String batchNo, BigDecimal colltTaskLmtTotal,
                                      int colltTasksTotal) throws Exception {
        logger.info("======>批量插入催收任务分配信息开始<======批次号为:"+batchNo);
        List<ColltTaskDistrVO> ctdBatchInsertList = new ArrayList<>();
        Iterator<String> handTypes = divCaseResult.keySet().iterator();
        while(handTypes.hasNext()){
            String handType = handTypes.next();
            ctdBatchInsertList.addAll(creColltTaskDistrList(divCaseResult.get(handType), batchNo, handType, colltTaskLmtTotal, colltTasksTotal));
        }
        int output = colltTaskDistrService.batchInsert(ctdBatchInsertList);

        if (output <= 0) {
            throw new Exception("批量插入催收任务分配信息失败！");
        }
        logger.info("======>批量插入催收任务分配信息结束<======批次号为:"+batchNo);
    }

    /**
     * 获取所有催收任务的分案结果
     * @param colltTasksGroupByHandType 按照手别分组的催收任务
     * @param orgCaseRatiosByHandType   按照手别分组的案件分配占比
     * @return
     * @throws Exception
     */
    private Map<String, Map<CaseDistrRatioVO, List<ColltTaskInfoVO>>> getDivCaseResult(Map<String, List<ColltTaskInfoVO>> colltTasksGroupByHandType,
                                                                                       Map<String, List<CaseDistrRatioVO>> orgCaseRatiosByHandType) throws Exception {
        Map<String, Map<CaseDistrRatioVO, List<ColltTaskInfoVO>>> result = new HashMap<>();

        for(String handType : allHandTypeList){
            Map<CaseDistrRatioVO, List<ColltTaskInfoVO>> distrMap = distrColltTasksToOrg(colltTasksGroupByHandType.get(handType),
                    orgCaseRatiosByHandType.get(handType), handType);
            result.put(handType, distrMap);
        }
        return result;
    }



    /**
     * 根据不同手别的催收任务，给不同手别的案件占比的委外机构分案
     *
     * @param colltTasks 参与分案的所有催收任务
     * @param caseDistrs 不同手别的案件占比
     * @param handType   委外经手类型
     * @return
     */
    private Map<CaseDistrRatioVO, List<ColltTaskInfoVO>> distrColltTasksToOrg(List<ColltTaskInfoVO> colltTasks, List<CaseDistrRatioVO> caseDistrs, String handType) throws Exception {
        Map<CaseDistrRatioVO, List<ColltTaskInfoVO>> result = new HashMap<>();
        try{
            if((Objects.isNull(colltTasks) || colltTasks.isEmpty()) || (Objects.isNull(caseDistrs) || caseDistrs.isEmpty())){
                return result;
            }
            BigDecimal distrColltTaskTotal = new BigDecimal(colltTasks.size());

            /**
             * wanglihua
             * 2020-01-07
             * 修改分案方式，是大金额案件尽可能平均分配
             *
             * */
            //分离出由大到小排序的大于金额5w的案件
            List<ColltTaskInfoVO> largeLmtCasesList = colltTasks.stream().filter(a -> divisionLmt.compareTo(a.getOverLmt()) == -1 || divisionLmt.compareTo(a.getOverLmt()) == 0).collect(Collectors.toList());
            //分离出由大到小排序的小于金额5w的案件
            List<ColltTaskInfoVO> smallLmtCasesList = colltTasks.stream().filter(a -> divisionLmt.compareTo(a.getOverLmt()) > -1 && divisionLmt.compareTo(a.getOverLmt()) != 0).collect(Collectors.toList());
            //大额案件总量
            int largeLmtCasesTotal = largeLmtCasesList.size();
            //小额案件总量
            int smallLmtCasesTotal = smallLmtCasesList.size();
            //机构总数
            BigDecimal caseDistrsTotal = new BigDecimal(caseDistrs.size());
            //计算每个机构分得大额案件数量的平均值，若不足整数则从小额案件里补足
            int remainCases = largeLmtCasesTotal % caseDistrsTotal.intValue();
            int aveCases = largeLmtCasesTotal / caseDistrsTotal.intValue();
            if (remainCases > 0) {
                aveCases += 1;
                for (int i = 1; i <= caseDistrsTotal.intValue() - remainCases; i++) {
                    if (smallLmtCasesList.size() > 0) {
                        largeLmtCasesList.add(smallLmtCasesList.get(0));
                        smallLmtCasesList.remove(0);
                    }
                }
            }
            //对大额案件的案件数进行分组
            List<List<ColltTaskInfoVO>> spiltCaseList = Stream.iterate(0, n -> n + 1)
                    .limit(aveCases)
                    .parallel()
                    .map(a -> largeLmtCasesList.stream()
                            .skip(a * caseDistrsTotal.intValue())
                            .limit(caseDistrsTotal.intValue())
                            .parallel()
                            .collect(Collectors.toList()))
                    .collect(Collectors.toList());

            //先分配大额案件
            for (int i = 0; i < caseDistrsTotal.intValue(); i++) {
                //接收案件
                List<ColltTaskInfoVO> aveRs = new ArrayList<>();
                //机构分配的案件数
                int divCaseNum = distrColltTaskTotal.multiply(getCaseDistrRatio(caseDistrs.get(i), handType)).intValue();
                for (int m = 0; m < aveCases; m++) {
                    if (divCaseNum > aveRs.size()) {
                        aveRs.add(spiltCaseList.get(m).get(0));
                        spiltCaseList.get(m).remove(0);
                    }
                }
                //存入中间Map
                result.put(caseDistrs.get(i),aveRs);
            }
            //将未分配的大额案件并入小额案件
            for (int m = 0; m < aveCases; m++) {
                smallLmtCasesList.addAll(spiltCaseList.get(m));
            }
            /***********2020-01-07修改结束*****************/
            /**
             * 案件分配比从小到大排序，催收任务金额从小到大排序，能分配到比较多催收任务的，剩下的自动给该机构，这里主要避免出现分配的任务数总和大于参与分案的任务总数
             * 比如：参与分案的机构一手案件分配比有0.3、0.4、0.16、0.0.14，参与案件分配的总数为299
             * 那么分配数为90、120、48、42，分配数总和则为300 > 299
             */
            for (int i = 0; i < caseDistrs.size() - 1; i++) {
                List<ColltTaskInfoVO> temp = new ArrayList<>();
                int orgHaveTaskNum = distrColltTaskTotal.multiply(getCaseDistrRatio(caseDistrs.get(i), handType)).intValue();
                for (int j = 0; j < orgHaveTaskNum - aveCases; j++) {
                    temp.add(smallLmtCasesList.get(smallLmtCasesList.size() - 1));
                    smallLmtCasesList.remove(smallLmtCasesList.size() - 1);
                }
//                result.put(caseDistrs.get(i), temp);
                result.get(caseDistrs.get(i)).addAll(temp);//2020-01-07修改
            }
//            result.put(caseDistrs.get(caseDistrs.size() - 1), smallLmtCasesList);
            int orgHaveTaskNum = distrColltTaskTotal.multiply(getCaseDistrRatio(caseDistrs.get(caseDistrs.size() - 1), handType)).intValue();
            for (int i = 0; i < orgHaveTaskNum - aveCases; i++) {
                if (smallLmtCasesList.size() > 0) {
                    result.get(caseDistrs.get(caseDistrs.size() - 1)).add(smallLmtCasesList.get(0));
                    smallLmtCasesList.remove(0);
                }
            }
            //若还有剩下的统一分给第一个分案比例大于0的机构---20201119lmj
            int orgNum=0;
            while(smallLmtCasesList.size() > 0 && !smallLmtCasesList.isEmpty() && orgNum<caseDistrs.size()){
                if(getCaseDistrRatio(caseDistrs.get(orgNum), handType).compareTo(BigDecimal.ZERO) >0){
                    result.get(caseDistrs.get(orgNum)).addAll(smallLmtCasesList);
                    break;
                }
                orgNum++;
            }
            //若还有剩下的统一分给第一个分案机构
            //if (smallLmtCasesList.size() > 0 && !smallLmtCasesList.isEmpty()) result.get(caseDistrs.get(0)).addAll(smallLmtCasesList);
        } catch (Exception e){
            e.printStackTrace();
            throw new Exception("======>对催收任务进行分案出错，错误信息为:" +e.getMessage());
        }
        return result;
    }

    /**
     * 根据手别获取对应的案件分配比
     *
     * @param caseDistrRatioVO
     * @param handType
     * @return
     */
    private BigDecimal getCaseDistrRatio(CaseDistrRatioVO caseDistrRatioVO, String handType) {
        BigDecimal result = BigDecimal.ZERO;
        switch (handType) {
            case oneHand:
                result = caseDistrRatioVO.getPrimCaseRatio();
                break;
            case twoHand:
                result = caseDistrRatioVO.getSecdCaseRatio();
                break;
            case threeHand:
                result = caseDistrRatioVO.getThdCaseRatio();
                break;
            case longHand:
                result = caseDistrRatioVO.getLongAgeCaseRatio();
                break;
        }
        return result;
    }

    /**
     * 组装催收任务分配信息
     *
     * @param difHandTyOrgHadCtTks 不同手别的分案结果
     * @param batchNo              批次号
     * @param handType             委外经手类型
     * @param colltTaskLmtTotal    参与分案的催收任务总金额
     * @param  colltTasksTotal     参与分案的催收任务总数
     * @return
     */
    private List<ColltTaskDistrVO> creColltTaskDistrList(Map<CaseDistrRatioVO, List<ColltTaskInfoVO>> difHandTyOrgHadCtTks, String batchNo,
                                                         String handType, BigDecimal colltTaskLmtTotal, int colltTasksTotal) {
        List<ColltTaskDistrVO> resultList = new ArrayList<>();
        Iterator<CaseDistrRatioVO> iterator = difHandTyOrgHadCtTks.keySet().iterator();
        while(iterator.hasNext()){
            CaseDistrRatioVO cdrVO = iterator.next();
            BigDecimal orgHadLmtTotal = difHandTyOrgHadCtTks.get(cdrVO).stream().map(ColltTaskInfoVO::getOverLmt).reduce(BigDecimal.ZERO, BigDecimal::add);
            ColltTaskDistrVO colltTaskDistrVO = new ColltTaskDistrVO();
            setUserInfoToVO(colltTaskDistrVO);
            colltTaskDistrVO.setColltBatchNo(batchNo);
            colltTaskDistrVO.setOutsOrgCode(cdrVO.getCooprOrgNo());
            colltTaskDistrVO.setOutsOrgName(cdrVO.getCooprOrgName());
            colltTaskDistrVO.setColltWay(RiskColltConstant.STD_COLLT_WAY_03);
            colltTaskDistrVO.setOutsHdleType(handType);
            colltTaskDistrVO.setDistrLmt(orgHadLmtTotal);
            colltTaskDistrVO.setDistrTaskNum(String.valueOf(difHandTyOrgHadCtTks.get(cdrVO).size()));
            colltTaskDistrVO.setDistrLmtRatio(orgHadLmtTotal.divide(colltTaskLmtTotal, 4, BigDecimal.ROUND_HALF_UP));
            //System.out.println("------------------------ " + flowCommonService.getMarkSaid(difHandTyOrgHadCtTks.get(cdrVO).size(), colltTasksTotal));
            colltTaskDistrVO.setDistrTasksRatio(getCaseDistrRatio(cdrVO, handType));
            colltTaskDistrVO.setDistrTime(TimeUtil.getCurrentDateTime());
            colltTaskDistrVO.setOpUserCode(colltTaskDistrVO.getLoginUserId());
            colltTaskDistrVO.setOpOrgCode(colltTaskDistrVO.getLoginUserOrgCode());
            colltTaskDistrVO.setCreateUser(colltTaskDistrVO.getLoginUserId());
            colltTaskDistrVO.setCreateTime(TimeUtil.getCurrentDateTime());
            colltTaskDistrVO.setLastChgUsr(colltTaskDistrVO.getLoginUserId());
            colltTaskDistrVO.setIsPassDistr(BaseConstant.NO_N);

            resultList.add(colltTaskDistrVO);
        }

        return resultList;
    }

    /**
     * 组装需要更新的催收任务信息
     *
     * @param allDistrResultMap  所有手别的分案结果
     * @param batchNo            分配批次号
     * @return
     */
    private void updateColltTaskInfos(Map<String, Map<CaseDistrRatioVO, List<ColltTaskInfoVO>>> allDistrResultMap, OutsTaskDistrMainVO vo, String batchNo) {
        logger.info("======>批量更新催收任务信息开始<======批次号为:"+batchNo);
        List<ColltTaskInfoVO> updColltTaskInfoList = new ArrayList<>();
        Iterator<String> iterator = allDistrResultMap.keySet().iterator();
        while (iterator.hasNext()) {
            String hangType = iterator.next();
            Iterator<CaseDistrRatioVO> ctiVoIterator = allDistrResultMap.get(hangType).keySet().iterator();
            while(ctiVoIterator.hasNext()){
                CaseDistrRatioVO cdrVO = ctiVoIterator.next();
                List<ColltTaskInfoVO> colltTaskInfoTempList = Optional.ofNullable(allDistrResultMap.get(hangType).get(cdrVO)).orElse(new ArrayList<>());
                colltTaskInfoTempList.forEach(colltTaskInfoVO -> {
                    ColltTaskInfoVO ctiVO = new ColltTaskInfoVO();
                    ctiVO.setColltTaskNo(colltTaskInfoVO.getColltTaskNo());
                    ctiVO.setColltBatchNo(batchNo);
                    ctiVO.setOutsOrgCode(cdrVO.getCooprOrgNo());
                    ctiVO.setOutsOrgName(cdrVO.getCooprOrgName());
                    ctiVO.setIsTaskDistr(BaseConstant.YES_Y);
                    ctiVO.setIdentWay(RiskColltConstant.IDENT_WAY_02);
                    ctiVO.setOpUserCode(vo.getLoginUserId());
                    ctiVO.setOpOrgCode(vo.getLoginUserOrgCode());
                    ctiVO.setLastUpdateUser(vo.getLoginUserId());

                    updColltTaskInfoList.add(ctiVO);
                });
            }
        }
        if(null!=updColltTaskInfoList && !updColltTaskInfoList.isEmpty()){
            int num = colltTaskInfoService.batchUpdateVO(updColltTaskInfoList);
            if(num <= 0){
                logger.error("批量更新催收任务信息失败！");
            }
        }
        logger.info("======>批量更新催收任务信息结束<======批次号为:"+batchNo);
    }

}
